﻿using System.Threading;
using System.Threading.Tasks;
using ESRI.ArcGIS.Client.Geometry;
using ESRI.ArcGIS.Client.Tasks;

namespace ESRI.ArcGIS.Client.Async
{
    public static partial class LocatorExtensions
    {
        #region AddressToLocations

        /// <summary>
        /// Sends a request to the ArcGIS REST geocode resource to find candidates for a single address
        /// specified in the address argument.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="parameters">The various address fields accepted by the corresponding geocode service
        /// along with an optional list of fields to be included in the returned results.</param>
        /// <returns></returns>
        public static Task<AddressToLocationsTaskResult> AddressToLocationsTaskAsync(this Locator task,
            AddressToLocationsParameters parameters)
        {
            return AddressToLocationsTaskAsync(task, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Sends a request to the ArcGIS REST geocode resource to find candidates for a single address
        /// specified in the address argument.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="parameters">The various address fields accepted by the corresponding geocode service
        /// along with an optional list of fields to be included in the returned results.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<AddressToLocationsTaskResult> AddressToLocationsTaskAsync(this Locator task,
            AddressToLocationsParameters parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<Locator, AddressToLocationsEventArgs, AddressToLocationsTaskResult>(
                t => t.AddressToLocationsAsync(parameters),
                (t, e) => t.AddressToLocationsCompleted += e,
                (t, e) => t.AddressToLocationsCompleted -= e,
                e => new AddressToLocationsTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region LocationToAddress

        /// <summary>
        /// Sends a request to the ArcGIS REST geocode resource to Locates an address based on a given point.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="parameter">Paramter used to configure the request.</param>
        /// <returns></returns>
        public static Task<LocationToAddressTaskResult> LocationToAddressTaskAsync(this Locator task,
            LocationToAddressParameter parameter)
        {
            return LocationToAddressTaskAsync(task, parameter, CancellationToken.None);
        }

        /// <summary>
        /// Sends a request to the ArcGIS REST geocode resource to Locates an address based on a given point.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="parameter">Paramter used to configure the request.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<LocationToAddressTaskResult> LocationToAddressTaskAsync(this Locator task,
            LocationToAddressParameter parameter, CancellationToken cancellationToken)
        {
            return LocationToAddressTaskAsync(task, parameter.Location, parameter.Distance, cancellationToken);
        }

        /// <summary>
        /// Sends a request to the ArcGIS REST geocode resource to Locates an address based on a given point.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="location">The point at which to search for the closest address.
        /// The location should be in the same spatial reference as that of the geocode service.</param>
        /// <param name="distance">The distance in meters from the given location within which a matching address
        /// should be searched.</param>
        /// <returns></returns>
        public static Task<LocationToAddressTaskResult> LocationToAddressTaskAsync(this Locator task,
            MapPoint location, double distance)
        {
            return LocationToAddressTaskAsync(task, location, distance, CancellationToken.None);
        }

        /// <summary>
        /// Sends a request to the ArcGIS REST geocode resource to Locates an address based on a given point.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="location">The point at which to search for the closest address.
        /// The location should be in the same spatial reference as that of the geocode service.</param>
        /// <param name="distance">The distance in meters from the given location within which a matching address
        /// should be searched.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<LocationToAddressTaskResult> LocationToAddressTaskAsync(this Locator task,
            MapPoint location, double distance, CancellationToken cancellationToken)
        {
            return task.HandleTask<Locator, AddressEventArgs, LocationToAddressTaskResult>(
                t => t.LocationToAddressAsync(location, distance),
                (t, e) => t.LocationToAddressCompleted += e,
                (t, e) => t.LocationToAddressCompleted -= e,
                e => new LocationToAddressTaskResult(e),
                cancellationToken);
        }

        #endregion
    }
}
